﻿using System.Globalization;
using System.IO;
using System.Linq;
using Microsoft.CTS.HSG;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Lib.UnitTest
{


    /// <summary>
    ///This is a test class for ScriptingDriverTest and is intended
    ///to contain all ScriptingDriverTest Unit Tests
    ///</summary>
    [TestClass()]
    public class ScriptEngineTest
    {


        private TestContext testContextInstance;
        private const string Instance = ".\\vs2010";
        private const string Database = "AdventureWorks2008R2";
        private static string fileName;

        private ScriptEngineConfiguration config;
        private ScriptEngine engine;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return this.testContextInstance;
            }
            set
            {
                this.testContextInstance = value;
            }
        }

        [TestInitialize]
        public void TestInitialize()
        {
            this.TestContext.WriteLine(
              "Script saved to {0}",
              ScriptEngineTest.fileName
              );

            this.config = new ScriptEngineConfiguration();
            this.config.Instance = ScriptEngineTest.Instance;
            this.config.Database = ScriptEngineTest.Database;
            this.config.FileName = ScriptEngineTest.fileName;

            this.engine = new ScriptEngine();
            this.engine.ScriptProgress += (s, e) => this.ReportProgressEvent(e);
            this.engine.ScriptError += (s, e) => this.ReportErrorEvent(e);
        }

        [ClassInitialize]
        public static void ClassInitialize(
            TestContext context
            )
        {
            ScriptEngineTest.fileName = Path.Combine(
                Path.GetTempPath(),
                Database + ".sql"
                );

        }

        [TestMethod]
        public void GenerateScriptWithDefaultSettings()
        {
            
            ScriptEngineConfiguration.ValidateConfiguration(
                this.config
                );

            Assert.IsFalse(this.config.Assemblies);
            Assert.IsFalse(this.config.OptimizerData);
            Assert.IsFalse(this.config.Statistics);

           this.engine.GenerateScript(
                this.config
                );

            Assert.IsTrue(
                File.Exists(fileName)
                );

            string[] lines = File.ReadAllLines(
                fileName
                );

            ScriptEngineTest.VerifyDefaultScript(
                lines
                );

            ScriptEngineTest.VerifyNoAssemblies(
             lines
             );

            ScriptEngineTest.VerifyNoDropStatements(
                lines
                );

            ScriptEngineTest.VerifyNoOptimizierData(
                lines
                );
        }

        private void ReportProgressEvent(
            ProgressReportEventArgs e
            )
        {
            this.testContextInstance.WriteLine(
                "OnProgress;Urn:{0};Parent:{1};SubTotal:{2};SubTotalCount:{3};Total:{4};TotalCount:{5}",
                e.Current,
                e.Parent,
                e.SubTotal,
                e.SubTotalCount,
                e.Total,
                e.TotalCount
                );
        }

        private void ReportErrorEvent(
            ScriptingErrorEventArgs e
            )
        {
            this.testContextInstance.WriteLine(
                "OnProgress;Urn:{0};InnerException:{1}",
                e.Current,
                e.InnerException
                );
        }

        [TestMethod]
        public void GenerateScriptWithOptimizerData()
        {

            ScriptEngineConfiguration.ValidateConfiguration(
                this.config
                );

            this.config.OptimizerData = true;

            Assert.IsFalse(this.config.Assemblies);
            Assert.IsTrue(this.config.OptimizerData);
            Assert.IsTrue(this.config.Statistics);

            this.engine.GenerateScript(
                this.config
                );

            Assert.IsTrue(
                File.Exists(fileName)
                );

            string[] lines = File.ReadAllLines(
                fileName
                );

            ScriptEngineTest.VerifyDefaultScript(
                lines
                );

            ScriptEngineTest.VerifyNoAssemblies(
            lines
            );

            ScriptEngineTest.VerifyNoDropStatements(
                lines
                );

            ScriptEngineTest.VerifyOptimizierData(
                lines
                );

        }

        private static void VerifyDefaultScript(
            string[] scriptLines
            )
        {
            ScriptEngineTest.VerifyStringCount(
               scriptLines,
               "CREATE DATABASE",
               1
               );

            ScriptEngineTest.VerifyStringCount(
                scriptLines,
                "CREATE FULLTEXT CATALOG",
                1
                );

            ScriptEngineTest.VerifyStringCount(
                scriptLines,
                "CREATE LOGIN",
                8
                );

            ScriptEngineTest.VerifyStringCount(
                scriptLines,
                "CREATE USER",
                0
                );

            ScriptEngineTest.VerifyStringCount(
                scriptLines,
                "CREATE ROLE",
                0
                );

            ScriptEngineTest.VerifyStringCount(
                scriptLines,
                "CREATE SCHEMA",
                5
                );

            ScriptEngineTest.VerifyStringCount(
                scriptLines,
                "CREATE PROCEDURE",
                10
                );

            ScriptEngineTest.VerifyStringCount(
                scriptLines,
                "CREATE PARTITION FUNCTION",
                0
                );

            ScriptEngineTest.VerifyStringCount(
               scriptLines,
               "CREATE TABLE",
               71
               );

            ScriptEngineTest.VerifyStringCount(
               scriptLines,
               "CREATE CLUSTERED INDEX",
               0
               );

            ScriptEngineTest.VerifyStringCount(
               scriptLines,
               "CREATE PARTITION SCHEME",
               0
               );

            ScriptEngineTest.VerifyStringCount(
               scriptLines,
               "CREATE NONCLUSTERED INDEX",
               36
               );

            ScriptEngineTest.VerifyStringCount(
               scriptLines,
               "CREATE view",
               0
               );

            ScriptEngineTest.VerifyStringCount(
              scriptLines,
              "CREATE UNIQUE CLUSTERED INDEX",
              3
              );

            ScriptEngineTest.VerifyStringCount(
              scriptLines,
              "CREATE PROCEDURE",
              10
              );

            ScriptEngineTest.VerifyStringCount(
              scriptLines,
              "create trigger",
              0
              );


            ScriptEngineTest.VerifyStringCount(
              scriptLines,
              "FILEGROUP",
              4
              );


            ScriptEngineTest.VerifyStringCount(
              scriptLines,
              "ALTER DATABASE [AdventureWorks2008R2] ADD FILEGROUP",
              0
              );

            ScriptEngineTest.VerifyStringCount(
              scriptLines,
              "GRANT",
              0
              );

            ScriptEngineTest.VerifyStringCount(
              scriptLines,
              "ALTER DATABASE",
              29
              );

            ScriptEngineTest.VerifyStringCount(
              scriptLines,
              "ALTER LOGIN",
              4
              );

            ScriptEngineTest.VerifyStringCount(
              scriptLines,
              "ALTER PARTITION SCHEME",
              0
              );

            ScriptEngineTest.VerifyStringCount(
              scriptLines,
              "ALTER PARTITION FUNCTION",
              0
              );

            ScriptEngineTest.VerifyStringCount(
              scriptLines,
              "ALTER AUTHORIZATION",
              118
              );

         
        }

        private static void VerifyNoDropStatements(
            string[] scriptLines
            )
        {
            ScriptEngineTest.VerifyStringCount(
            scriptLines,
            "DROP ",
            0
            );
        }

        private static void VerifyNoOptimizierData(
            string[] scriptLines
            )
        {
            ScriptEngineTest.VerifyStringCount(
             scriptLines,
             "CREATE STATISTICS",
             0
             );

            ScriptEngineTest.VerifyStringCount(
             scriptLines,
             "UPDATE STATISTICS",
             0
             );

            ScriptEngineTest.VerifyStringCount(
             scriptLines,
             "STATS_STREAM",
             0
             );

        }

        private static void VerifyOptimizierData(
            string[] scriptLines
            )
        {
            ScriptEngineTest.VerifyStringCount(
             scriptLines,
             "CREATE STATISTICS",
             41
             );

            ScriptEngineTest.VerifyStringCount(
             scriptLines,
             "UPDATE STATISTICS",
             169
             );

            ScriptEngineTest.VerifyStringCount(
             scriptLines,
             "STATS_STREAM",
             208
             );

        }

        private static void VerifyNoAssemblies(
            string[] scriptLines
            )
        {
            ScriptEngineTest.VerifyStringCount(
             scriptLines,
             "ASSEMBLY ",
             0
             );

        }

        private static void VerifyStringCount(
            string[] comparisonSource,
            string comparisonString,
            int expectedCount
            )
        {
            int actualCount = comparisonSource.Count(
                (s) =>
                {
                    return (s.Contains(comparisonString));
                }
                );

            string message = string.Format(
                CultureInfo.InvariantCulture,
                "Expected {0} instances of '{1}'; actual number of instances: {2}.",
                expectedCount,
                comparisonString,
                actualCount
                );

            Assert.AreEqual<int>(
                expectedCount,
                actualCount,
                message
                );

        }
    }
}
